//
/*   CUDA helper code
*    Copyright (C) 2009 Goffredo Marocchi
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "IGGS_CUDA_helper.h"
#include <cuda_runtime_api.h>
#include <cutil_inline.h>


/**\brief This function starts the cutil based timer
 * \param t reference to the timer object, unsigned int*
 * \return void
 */
void start_timer (unsigned int* t) {

	//cutilSafeCall(cutCreateTimer(&timer_t1));

	cutilCheckError(cutCreateTimer(t));
	cutilCheckError(cutStartTimer((*t)));

	return;
}

/**\brief This function stops the cutil based timer and converts the elapsed time into milliseconds
 * \param t reference to the timer object, unsigned int
 * \param t_ms reference to the variable used to store the timer's value into milliseconds, float*
 * \return void
 */
void stop_timer (unsigned int t, float * t_ms) {

	cutilCheckError(cutStopTimer(t));
	(*t_ms) = cutGetTimerValue(t);
	cutilCheckError(cutDeleteTimer(t));

	return;
}

/**\brief This function prints to STDOUT the amount of total device memory and the amount of free device memory
 * \return void
 */
extern "C" void gpu_print_free_memory_ () {

	//The following code is able to display the amount of free device memory at this current moment
    unsigned int total_memory;
    unsigned int free_memory;
    CUresult r;
    r = cuInit(0);
    send_msg("Init result     : %d\n",r); //the result should be 0
    r = cuMemGetInfo(&free_memory,&total_memory);
    send_msg("Mem info result : %d",r); //the result should be 0
    send_msg("Total memory: %f MB",(float)total_memory/(1024*1024));
    send_msg("Free memory: %f MB", (float)free_memory/(1024*1024));

	return;

}

/**\brief This function inits the CUDA device and prints to STDOUT the current CUDA device properties
 * \return void
 */
extern "C" void gpu_init_ () {

	//CUDA device set-up and initialization
    cudaDeviceProp device_properties;
    int dev_id = cutGetMaxGflopsDeviceId();
    cudaGetDeviceProperties( &device_properties, dev_id );

#ifdef _DEBUG
    //the CUDA device does not need to be manually set, default CUDA device (0) already selected.
    int gflops = 0;
    gflops = device_properties.multiProcessorCount * device_properties.clockRate;

    send_msg("Using device %d: %s", dev_id, device_properties.name);
    send_msg ("# of SM: %d", device_properties.multiProcessorCount);
    send_msg ("\nClock Speed: %d MHz", device_properties.clockRate/1000);
    send_msg ("\nPeak FP performance (MADD+MUL co-issue): %d GFLOPS", (gflops*8*3/1000000));
    send_msg ("\nPeak FP performance (MADD single-issue): %d GFLOPS\n", (gflops*8*2/1000000));
	//MADD+MUL co-issue -- 2 + 1 FP ops/cycle
#endif

	return;
}
